/** Copyright Notice:

    Copyright (C) 2011 Ivo Wingelaar

    This software is provided 'as-is', without any express or implied
    warranty.  In no event will the authors be held liable for any damages
    arising from the use of this software.

    Permission is granted to anyone to use this software for any purpose,
    including commercial applications, and to alter it and redistribute it
    freely, subject to the following restrictions:

    1.  The origin of this software must not be misrepresented; you must not
        claim that you wrote the original software. If you use this software
        in a product, an acknowledgment in the product documentation would be
        appreciated but is not required.
    2.  Altered source versions must be plainly marked as such, and must not be
        misrepresented as being the original software.
    3.  This notice may not be removed or altered from any source distribution.

    Please note that the Myth Library is based in part on the work of Nikolaus
    Gebhardt (Irrlicht Engine) and I give full credits to him, and the people who
    helped him for making available an excellent piece of code.

**/

//
// MythCryptoHashFunctionSHA_C.cpp 010: implementation of the SHA hash algorithms
//

#include "MythCrypto_HashFunctionSHA_C.hpp"

#define K32(p) (((uint32_t*)data)[p])
#define K64(p) (((uint64_t*)data)[p])

#define ROL32(x,n) ((x << n) | (x >> (32-n)))
#define ROR32(x,n) ((x >> n) | (x << (32-n)))
#define ROR64(x,n) ((x >> n) | (x << (64-n)))

#define SHA1F(x,y,z) (z ^ (x & (y ^ z)))
#define SHA1G(x,y,z) (x ^ y ^ z)
#define SHA1H(x,y,z) ((x & y) | (z & (x | y)))
#define SHA1R(t) (q = W[((t)-3) & 0x0f] ^ W[((t)-8) & 0x0f] ^ W[((t)-14) & 0x0f] ^ W[(t) & 0x0f], (W[(t) & 0x0f] = ROL32(q,1)))
#define SHA1Subround(f,a,b,c,d,e,x,k) e += ROL32(a,5) + f(b,c,d) + k + x; b = ROL32(b,30);

#define SHA2S0(x) (ROR32(x, 7) ^ ROR32(x,18) ^  (x >> 3))
#define SHA2S1(x) (ROR32(x,17) ^ ROR32(x,19) ^  (x >> 10))
#define SHA2S2(x) (ROR32(x, 2) ^ ROR32(x,13) ^ ROR32(x,22))
#define SHA2S3(x) (ROR32(x, 6) ^ ROR32(x,11) ^ ROR32(x,25))
#define SHA2Subround(a,b,c,d,e,f,g,h,x,k) {uint32_t t = h + SHA2S3(e) + (g ^ (e & (f ^ g))) + k + x; d += t; h = t + SHA2S2(a) + ((a & b) | (c & (a | b)));}

#define SHA4S0(x) (ROR64(x, 1) ^ ROR64(x, 8) ^  (x >> 7))
#define SHA4S1(x) (ROR64(x,19) ^ ROR64(x,61) ^  (x >> 6))
#define SHA4S2(x) (ROR64(x,28) ^ ROR64(x,34) ^ ROR64(x,39))
#define SHA4S3(x) (ROR64(x,14) ^ ROR64(x,18) ^ ROR64(x,41))
#define SHA4Subround(a,b,c,d,e,f,g,h,x,k) {uint64_t t = h + SHA4S3(e) + (g ^ (e & (f ^ g))) + k + x; d += t; h = t + SHA4S2(a) + ((a & b) | (c & (a | b)));}

static const uint32_t SHA1C[4] =
{
    0x5a827999, 0x6ed9eba1, 0x8f1bbcdc, 0xca62c1d6
};

static const uint32_t SHA2C[64] =
{
    0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5,
    0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
    0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3,
    0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
    0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc,
    0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
    0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7,
    0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
    0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13,
    0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
    0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3,
    0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
    0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5,
    0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
    0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208,
    0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
};

static const uint64_t SHA4C[80] =
{
    0x428a2f98d728ae22ULL, 0x7137449123ef65cdULL, 0xb5c0fbcfec4d3b2fULL, 0xe9b5dba58189dbbcULL,
    0x3956c25bf348b538ULL, 0x59f111f1b605d019ULL, 0x923f82a4af194f9bULL, 0xab1c5ed5da6d8118ULL,
    0xd807aa98a3030242ULL, 0x12835b0145706fbeULL, 0x243185be4ee4b28cULL, 0x550c7dc3d5ffb4e2ULL,
    0x72be5d74f27b896fULL, 0x80deb1fe3b1696b1ULL, 0x9bdc06a725c71235ULL, 0xc19bf174cf692694ULL,
    0xe49b69c19ef14ad2ULL, 0xefbe4786384f25e3ULL, 0x0fc19dc68b8cd5b5ULL, 0x240ca1cc77ac9c65ULL,
    0x2de92C6f592b0275ULL, 0x4a7484aa6ea6e483ULL, 0x5cb0a9dcbd41fbd4ULL, 0x76f988da831153b5ULL,
    0x983e5152ee66dfabULL, 0xa831c66d2db43210ULL, 0xb00327c898fb213fULL, 0xbf597fc7beef0ee4ULL,
    0xC6e00bf33da88fc2ULL, 0xd5a79147930aa725ULL, 0x06ca6351e003826fULL, 0x142929670a0e6e70ULL,
    0x27b70a8546d22ffcULL, 0x2e1b21385c26c926ULL, 0x4d2c6dfc5ac42aedULL, 0x53380d139d95b3dfULL,
    0x650a73548baf63deULL, 0x766a0abb3c77b2a8ULL, 0x81c2c92e47edaee6ULL, 0x92722c851482353bULL,
    0xa2bfe8a14cf10364ULL, 0xa81a664bbc423001ULL, 0xc24b8b70d0f89791ULL, 0xc76c51a30654be30ULL,
    0xd192e819d6ef5218ULL, 0xd69906245565a910ULL, 0xf40e35855771202aULL, 0x106aa07032bbd1b8ULL,
    0x19a4c116b8d2d0c8ULL, 0x1e376c085141ab53ULL, 0x2748774cdf8eeb99ULL, 0x34b0bcb5e19b48a8ULL,
    0x391c0cb3c5c95a63ULL, 0x4ed8aa4ae3418acbULL, 0x5b9cca4f7763e373ULL, 0x682e6ff3d6b2b8a3ULL,
    0x748f82ee5defb2fcULL, 0x78a5636f43172f60ULL, 0x84c87814a1f0ab72ULL, 0x8cc702081a6439ecULL,
    0x90befffa23631e28ULL, 0xa4506cebde82bde9ULL, 0xbef9a3f7b2c67915ULL, 0xc67178f2e372532bULL,
    0xca273eceea26619cULL, 0xd186b8c721c0c207ULL, 0xeada7dd6cde0eb1eULL, 0xf57d4f7fee6ed178ULL,
    0x06f067aa72176fbaULL, 0x0a637dc5a2c898a6ULL, 0x113f9804bef90daeULL, 0x1b710b35131c471bULL,
    0x28db77f523047d84ULL, 0x32caab7b40c72493ULL, 0x3c9ebe0a15c9bebcULL, 0x431d67c49c100d4cULL,
    0x4cc5d4becb3e42b6ULL, 0x597f299cfc657e2aULL, 0x5fcb6fab3ad6faecULL, 0x6c44198c4a475817ULL
};

namespace Myth
{
namespace Crypto
{

/** constructor **/
HashFunctionSHA1_C::HashFunctionSHA1_C() :
    HashFunctionStub_C(20, 64)
{
    reset();
}

/** destructor **/
HashFunctionSHA1_C::~HashFunctionSHA1_C()
{
    //
}

/** virtual function **/
/** reset            **/
//! Resets the object, it can be used again for other data.
/// \return void
/// \param  void
void HashFunctionSHA1_C::reset(void)
{
    HashFunctionStub_C::reset_b();
    mState[0] = 0x67452301;
    mState[1] = 0xefcdab89;
    mState[2] = 0x98badcfe;
    mState[3] = 0x10325476;
    mState[4] = 0xc3d2e1f0;
}

/** virtual function **/
/** transform_block  **/
//! Feeds a new block of data in the digester.
/// \return void
/// \param   uint8_t *data
///         Pointer to a piece of data of get_transform_size size.
void HashFunctionSHA1_C::transform_block( uint8_t *data)
{
    uint32_t q, W[80];

    W[ 0] = byteswap(K32( 0));
    W[ 1] = byteswap(K32( 1));
    W[ 2] = byteswap(K32( 2));
    W[ 3] = byteswap(K32( 3));
    W[ 4] = byteswap(K32( 4));
    W[ 5] = byteswap(K32( 5));
    W[ 6] = byteswap(K32( 6));
    W[ 7] = byteswap(K32( 7));
    W[ 8] = byteswap(K32( 8));
    W[ 9] = byteswap(K32( 9));
    W[10] = byteswap(K32(10));
    W[11] = byteswap(K32(11));
    W[12] = byteswap(K32(12));
    W[13] = byteswap(K32(13));
    W[14] = byteswap(K32(14));
    W[15] = byteswap(K32(15));

    uint32_t A = mState[0];
    uint32_t B = mState[1];
    uint32_t C = mState[2];
    uint32_t D = mState[3];
    uint32_t E = mState[4];

    SHA1Subround(SHA1F, A, B, C, D, E, W[ 0], SHA1C[0]);
    SHA1Subround(SHA1F, E, A, B, C, D, W[ 1], SHA1C[0]);
    SHA1Subround(SHA1F, D, E, A, B, C, W[ 2], SHA1C[0]);
    SHA1Subround(SHA1F, C, D, E, A, B, W[ 3], SHA1C[0]);
    SHA1Subround(SHA1F, B, C, D, E, A, W[ 4], SHA1C[0]);
    SHA1Subround(SHA1F, A, B, C, D, E, W[ 5], SHA1C[0]);
    SHA1Subround(SHA1F, E, A, B, C, D, W[ 6], SHA1C[0]);
    SHA1Subround(SHA1F, D, E, A, B, C, W[ 7], SHA1C[0]);
    SHA1Subround(SHA1F, C, D, E, A, B, W[ 8], SHA1C[0]);
    SHA1Subround(SHA1F, B, C, D, E, A, W[ 9], SHA1C[0]);
    SHA1Subround(SHA1F, A, B, C, D, E, W[10], SHA1C[0]);
    SHA1Subround(SHA1F, E, A, B, C, D, W[11], SHA1C[0]);
    SHA1Subround(SHA1F, D, E, A, B, C, W[12], SHA1C[0]);
    SHA1Subround(SHA1F, C, D, E, A, B, W[13], SHA1C[0]);
    SHA1Subround(SHA1F, B, C, D, E, A, W[14], SHA1C[0]);
    SHA1Subround(SHA1F, A, B, C, D, E, W[15], SHA1C[0]);
    SHA1Subround(SHA1F, E, A, B, C, D, SHA1R(16), SHA1C[0]);
    SHA1Subround(SHA1F, D, E, A, B, C, SHA1R(17), SHA1C[0]);
    SHA1Subround(SHA1F, C, D, E, A, B, SHA1R(18), SHA1C[0]);
    SHA1Subround(SHA1F, B, C, D, E, A, SHA1R(19), SHA1C[0]);

    for(uint32_t i = 20; i < 40; i+=5)
    {
        SHA1Subround(SHA1G, A, B, C, D, E, SHA1R(  i), SHA1C[1]);
        SHA1Subround(SHA1G, E, A, B, C, D, SHA1R(i+1), SHA1C[1]);
        SHA1Subround(SHA1G, D, E, A, B, C, SHA1R(i+2), SHA1C[1]);
        SHA1Subround(SHA1G, C, D, E, A, B, SHA1R(i+3), SHA1C[1]);
        SHA1Subround(SHA1G, B, C, D, E, A, SHA1R(i+4), SHA1C[1]);
    }

    for(uint32_t i = 40; i < 60; i+=5)
    {
        SHA1Subround(SHA1H, A, B, C, D, E, SHA1R(i  ), SHA1C[2]);
        SHA1Subround(SHA1H, E, A, B, C, D, SHA1R(i+1), SHA1C[2]);
        SHA1Subround(SHA1H, D, E, A, B, C, SHA1R(i+2), SHA1C[2]);
        SHA1Subround(SHA1H, C, D, E, A, B, SHA1R(i+3), SHA1C[2]);
        SHA1Subround(SHA1H, B, C, D, E, A, SHA1R(i+4), SHA1C[2]);
    }

    for(uint32_t i = 60; i < 80; i+=5)
    {
        SHA1Subround(SHA1G, A, B, C, D, E, SHA1R(i  ), SHA1C[3]);
        SHA1Subround(SHA1G, E, A, B, C, D, SHA1R(i+1), SHA1C[3]);
        SHA1Subround(SHA1G, D, E, A, B, C, SHA1R(i+2), SHA1C[3]);
        SHA1Subround(SHA1G, C, D, E, A, B, SHA1R(i+3), SHA1C[3]);
        SHA1Subround(SHA1G, B, C, D, E, A, SHA1R(i+4), SHA1C[3]);
    }

    mState[0] += A;
    mState[1] += B;
    mState[2] += C;
    mState[3] += D;
    mState[4] += E;
}

/** virtual function **/
/** finish           **/
//! Finishes the algorithm, no data can be fed again.
/// \return void
/// \param  void
void HashFunctionSHA1_C::finish(void)
{
    uint8_t padding[64];
    uint8_t len[8];
    memset(padding, 0, 64);
    padding[0] = 0x80;

    ((uint32_t*)len)[0] = byteswap((uint32_t)(get_processed() >> 29));
    ((uint32_t*)len)[1] = byteswap((uint32_t)(get_processed() << 3));

    uint32_t buffered = get_processed() & 0x3F;
    uint32_t paddingn = (buffered < 56) ? (56 - buffered) : (120 - buffered);

    feed(padding, paddingn);
    feed(len, 8);

    mState[0] = byteswap(mState[0]);
    mState[1] = byteswap(mState[1]);
    mState[2] = byteswap(mState[2]);
    mState[3] = byteswap(mState[3]);
    mState[4] = byteswap(mState[4]);
}

/** virtual function **/
/** get_hash         **/
//! Returns the hash.
/// \return void
/// \param   uint8_t *hash
///         A pointer to a location where you want to store the hash.
void HashFunctionSHA1_C::get_hash( uint8_t *hash)
{
    for(uint32_t a = 0; a < 20; a++)
        hash[a] = ((uint8_t*)mState)[a];
}

/** constructor **/
HashFunctionSHA256_C::HashFunctionSHA256_C() :
    HashFunctionStub_C(32, 64)
{
    reset();
}

/** destructor **/
HashFunctionSHA256_C::~HashFunctionSHA256_C()
{
    //
}

/** virtual function **/
/** reset            **/
//! Resets the object, it can be used again for other data.
/// \return void
/// \param  void
void HashFunctionSHA256_C::reset(void)
{
    HashFunctionStub_C::reset_b();
    mState[0] = 0x6a09e667;
    mState[1] = 0xbb67ae85;
    mState[2] = 0x3c6ef372;
    mState[3] = 0xa54ff53a;
    mState[4] = 0x510e527f;
    mState[5] = 0x9b05688c;
    mState[6] = 0x1f83d9ab;
    mState[7] = 0x5be0cd19;
}

/** virtual function **/
/** transform_block  **/
//! Feeds a new block of data in the digester.
/// \return void
/// \param   uint8_t *data
///         Pointer to a piece of data of get_transform_size size.
void HashFunctionSHA256_C::transform_block( uint8_t *data)
{
    uint32_t W[64];

    W[ 0] = byteswap(K32( 0));
    W[ 1] = byteswap(K32( 1));
    W[ 2] = byteswap(K32( 2));
    W[ 3] = byteswap(K32( 3));
    W[ 4] = byteswap(K32( 4));
    W[ 5] = byteswap(K32( 5));
    W[ 6] = byteswap(K32( 6));
    W[ 7] = byteswap(K32( 7));
    W[ 8] = byteswap(K32( 8));
    W[ 9] = byteswap(K32( 9));
    W[10] = byteswap(K32(10));
    W[11] = byteswap(K32(11));
    W[12] = byteswap(K32(12));
    W[13] = byteswap(K32(13));
    W[14] = byteswap(K32(14));
    W[15] = byteswap(K32(15));

    for(uint32_t i = 16; i < 64; i++)
        W[i] = SHA2S1(W[i-2]) + W[i-7] + SHA2S0(W[i-15]) + W[i-16];

    uint32_t a = mState[0];
    uint32_t b = mState[1];
    uint32_t c = mState[2];
    uint32_t d = mState[3];
    uint32_t e = mState[4];
    uint32_t f = mState[5];
    uint32_t g = mState[6];
    uint32_t h = mState[7];

    for(uint32_t i = 0; i < 64; i += 8)
    {
        SHA2Subround(a, b, c, d, e, f, g, h, W[  i], SHA2C[  i]);
        SHA2Subround(h, a, b, c, d, e, f, g, W[i+1], SHA2C[i+1]);
        SHA2Subround(g, h, a, b, c, d, e, f, W[i+2], SHA2C[i+2]);
        SHA2Subround(f, g, h, a, b, c, d, e, W[i+3], SHA2C[i+3]);
        SHA2Subround(e, f, g, h, a, b, c, d, W[i+4], SHA2C[i+4]);
        SHA2Subround(d, e, f, g, h, a, b, c, W[i+5], SHA2C[i+5]);
        SHA2Subround(c, d, e, f, g, h, a, b, W[i+6], SHA2C[i+6]);
        SHA2Subround(b, c, d, e, f, g, h, a, W[i+7], SHA2C[i+7]);
    }

    mState[0] += a;
    mState[1] += b;
    mState[2] += c;
    mState[3] += d;
    mState[4] += e;
    mState[5] += f;
    mState[6] += g;
    mState[7] += h;
}

/** virtual function **/
/** finish           **/
//! Finishes the algorithm, no data can be fed again.
/// \return void
/// \param  void
void HashFunctionSHA256_C::finish(void)
{
    uint8_t padding[64];
    uint8_t len[8];
    memset(padding, 0, 64);
    padding[0] = 0x80;

    ((uint32_t*)len)[0] = byteswap((uint32_t)(get_processed() >> 29));
    ((uint32_t*)len)[1] = byteswap((uint32_t)(get_processed() << 3));

    uint32_t buffered = get_processed() & 0x3F;
    uint32_t paddingn = (buffered < 56) ? (56 - buffered) : (120 - buffered);

    feed(padding, paddingn);
    feed(len, 8);

    mState[0] = byteswap(mState[0]);
    mState[1] = byteswap(mState[1]);
    mState[2] = byteswap(mState[2]);
    mState[3] = byteswap(mState[3]);
    mState[4] = byteswap(mState[4]);
    mState[5] = byteswap(mState[5]);
    mState[6] = byteswap(mState[6]);
    mState[7] = byteswap(mState[7]);
}

/** virtual function **/
/** get_hash         **/
//! Returns the hash.
/// \return void
/// \param   uint8_t *hash
///         A pointer to a location where you want to store the hash.
void HashFunctionSHA256_C::get_hash( uint8_t *hash)
{
    for(uint32_t a = 0; a < 32; a++)
        hash[a] = ((uint8_t*)mState)[a];
}

/** constructor **/
HashFunctionSHA224_C::HashFunctionSHA224_C() :
    HashFunctionStub_C(28, 64)
{
    reset();
}

/** destructor **/
HashFunctionSHA224_C::~HashFunctionSHA224_C()
{
    //
}

/** virtual function **/
/** reset            **/
//! Resets the object, it can be used again for other data.
/// \return void
/// \param  void
void HashFunctionSHA224_C::reset(void)
{
    HashFunctionStub_C::reset_b();
    mState[0] = 0xc1059ed8;
    mState[1] = 0x367cd507;
    mState[2] = 0x3070dd17;
    mState[3] = 0xf70e5939;
    mState[4] = 0xffc00b31;
    mState[5] = 0x68581511;
    mState[6] = 0x64f98fa7;
    mState[7] = 0xbefa4fa4;
}

/** virtual function **/
/** transform_block  **/
//! Feeds a new block of data in the digester.
/// \return void
/// \param   uint8_t *data
///         Pointer to a piece of data of get_transform_size size.
void HashFunctionSHA224_C::transform_block( uint8_t *data)
{
    uint32_t W[64];

    W[ 0] = byteswap(K32( 0));
    W[ 1] = byteswap(K32( 1));
    W[ 2] = byteswap(K32( 2));
    W[ 3] = byteswap(K32( 3));
    W[ 4] = byteswap(K32( 4));
    W[ 5] = byteswap(K32( 5));
    W[ 6] = byteswap(K32( 6));
    W[ 7] = byteswap(K32( 7));
    W[ 8] = byteswap(K32( 8));
    W[ 9] = byteswap(K32( 9));
    W[10] = byteswap(K32(10));
    W[11] = byteswap(K32(11));
    W[12] = byteswap(K32(12));
    W[13] = byteswap(K32(13));
    W[14] = byteswap(K32(14));
    W[15] = byteswap(K32(15));

    for(uint32_t i = 16; i < 64; i++)
        W[i] = SHA2S1(W[i-2]) + W[i-7] + SHA2S0(W[i-15]) + W[i-16];

    uint32_t a = mState[0];
    uint32_t b = mState[1];
    uint32_t c = mState[2];
    uint32_t d = mState[3];
    uint32_t e = mState[4];
    uint32_t f = mState[5];
    uint32_t g = mState[6];
    uint32_t h = mState[7];

    for(uint32_t i = 0; i < 64; i += 8)
    {
        SHA2Subround(a, b, c, d, e, f, g, h, W[  i], SHA2C[  i]);
        SHA2Subround(h, a, b, c, d, e, f, g, W[i+1], SHA2C[i+1]);
        SHA2Subround(g, h, a, b, c, d, e, f, W[i+2], SHA2C[i+2]);
        SHA2Subround(f, g, h, a, b, c, d, e, W[i+3], SHA2C[i+3]);
        SHA2Subround(e, f, g, h, a, b, c, d, W[i+4], SHA2C[i+4]);
        SHA2Subround(d, e, f, g, h, a, b, c, W[i+5], SHA2C[i+5]);
        SHA2Subround(c, d, e, f, g, h, a, b, W[i+6], SHA2C[i+6]);
        SHA2Subround(b, c, d, e, f, g, h, a, W[i+7], SHA2C[i+7]);
    }

    mState[0] += a;
    mState[1] += b;
    mState[2] += c;
    mState[3] += d;
    mState[4] += e;
    mState[5] += f;
    mState[6] += g;
    mState[7] += h;
}

/** virtual function **/
/** finish           **/
//! Finishes the algorithm, no data can be fed again.
/// \return void
/// \param  void
void HashFunctionSHA224_C::finish(void)
{
    uint8_t padding[64];
    uint8_t len[8];
    memset(padding, 0, 64);
    padding[0] = 0x80;

    ((uint32_t*)len)[0] = byteswap((uint32_t)(get_processed() >> 29));
    ((uint32_t*)len)[1] = byteswap((uint32_t)(get_processed() << 3));

    uint32_t buffered = get_processed() & 0x3F;
    uint32_t paddingn = (buffered < 56) ? (56 - buffered) : (120 - buffered);

    feed(padding, paddingn);
    feed(len, 8);

    mState[0] = byteswap(mState[0]);
    mState[1] = byteswap(mState[1]);
    mState[2] = byteswap(mState[2]);
    mState[3] = byteswap(mState[3]);
    mState[4] = byteswap(mState[4]);
    mState[5] = byteswap(mState[5]);
    mState[6] = byteswap(mState[6]);
}

/** virtual function **/
/** get_hash         **/
//! Returns the hash.
/// \return void
/// \param   uint8_t *hash
///         A pointer to a location where you want to store the hash.
void HashFunctionSHA224_C::get_hash( uint8_t *hash)
{
    for(uint32_t a = 0; a < 28; a++)
        hash[a] = ((uint8_t*)mState)[a];
}

/** constructor **/
HashFunctionSHA512_C::HashFunctionSHA512_C() :
    HashFunctionStub_C(64, 128)
{
    reset();
}

/** destructor **/
HashFunctionSHA512_C::~HashFunctionSHA512_C()
{
    //
}

/** virtual function **/
/** reset            **/
//! Resets the object, it can be used again for other data.
/// \return void
/// \param  void
void HashFunctionSHA512_C::reset(void)
{
    HashFunctionStub_C::reset_b();
    mState[0] = 0x6a09e667f3bcc908ULL;
    mState[1] = 0xbb67ae8584caa73bULL;
    mState[2] = 0x3c6ef372fe94f82bULL;
    mState[3] = 0xa54ff53a5f1d36f1ULL;
    mState[4] = 0x510e527fade682d1ULL;
    mState[5] = 0x9b05688c2b3e6c1fULL;
    mState[6] = 0x1f83d9abfb41bd6bULL;
    mState[7] = 0x5be0cd19137e2179ULL;
}

/** virtual function **/
/** transform_block  **/
//! Feeds a new block of data in the digester.
/// \return void
/// \param   uint8_t *data
///         Pointer to a piece of data of get_transform_size size.
void HashFunctionSHA512_C::transform_block( uint8_t *data)
{
    uint64_t W[80];

    W[ 0] = byteswap(K64( 0));
    W[ 1] = byteswap(K64( 1));
    W[ 2] = byteswap(K64( 2));
    W[ 3] = byteswap(K64( 3));
    W[ 4] = byteswap(K64( 4));
    W[ 5] = byteswap(K64( 5));
    W[ 6] = byteswap(K64( 6));
    W[ 7] = byteswap(K64( 7));
    W[ 8] = byteswap(K64( 8));
    W[ 9] = byteswap(K64( 9));
    W[10] = byteswap(K64(10));
    W[11] = byteswap(K64(11));
    W[12] = byteswap(K64(12));
    W[13] = byteswap(K64(13));
    W[14] = byteswap(K64(14));
    W[15] = byteswap(K64(15));

    for(uint32_t i = 16; i < 80; i++ )
        W[i] = SHA4S1(W[i-2]) + W[i-7] + SHA4S0(W[i-15]) + W[i-16];

    uint64_t a = mState[0];
    uint64_t b = mState[1];
    uint64_t c = mState[2];
    uint64_t d = mState[3];
    uint64_t e = mState[4];
    uint64_t f = mState[5];
    uint64_t g = mState[6];
    uint64_t h = mState[7];

    for(uint32_t i = 0; i < 80; i += 8)
    {
        SHA4Subround(a, b, c, d, e, f, g, h, W[i  ], SHA4C[i  ]);
        SHA4Subround(h, a, b, c, d, e, f, g, W[i+1], SHA4C[i+1]);
        SHA4Subround(g, h, a, b, c, d, e, f, W[i+2], SHA4C[i+2]);
        SHA4Subround(f, g, h, a, b, c, d, e, W[i+3], SHA4C[i+3]);
        SHA4Subround(e, f, g, h, a, b, c, d, W[i+4], SHA4C[i+4]);
        SHA4Subround(d, e, f, g, h, a, b, c, W[i+5], SHA4C[i+5]);
        SHA4Subround(c, d, e, f, g, h, a, b, W[i+6], SHA4C[i+6]);
        SHA4Subround(b, c, d, e, f, g, h, a, W[i+7], SHA4C[i+7]);
    }

    mState[0] += a;
    mState[1] += b;
    mState[2] += c;
    mState[3] += d;
    mState[4] += e;
    mState[5] += f;
    mState[6] += g;
    mState[7] += h;
}

/** virtual function **/
/** finish           **/
//! Finishes the algorithm, no data can be fed again.
/// \return void
/// \param  void
void HashFunctionSHA512_C::finish(void)
{
    uint8_t padding[128];
    uint8_t len[16];
    memset(padding, 0, 128);
    padding[0] = 0x80;

    ((uint64_t*)len)[0] = byteswap((uint64_t)(get_processed() >> 61));
    ((uint64_t*)len)[1] = byteswap((uint64_t)(get_processed() << 3));

    uint32_t buffered = get_processed() & 0x7F;
    uint32_t paddingn = (buffered < 112) ? (112 - buffered) : (240 - buffered);

    feed(padding, paddingn);
    feed(len, 16);

    mState[0] = byteswap(mState[0]);
    mState[1] = byteswap(mState[1]);
    mState[2] = byteswap(mState[2]);
    mState[3] = byteswap(mState[3]);
    mState[4] = byteswap(mState[4]);
    mState[5] = byteswap(mState[5]);
    mState[6] = byteswap(mState[6]);
    mState[7] = byteswap(mState[7]);
}

/** virtual function **/
/** get_hash         **/
//! Returns the hash.
/// \return void
/// \param   uint8_t *hash
///         A pointer to a location where you want to store the hash.
void HashFunctionSHA512_C::get_hash( uint8_t *hash)
{

    for(uint32_t a = 0; a < 64; a++)
        hash[a] = ((uint8_t*)mState)[a];
}

/** constructor **/
HashFunctionSHA384_C::HashFunctionSHA384_C() :
    HashFunctionStub_C(48, 128)
{
    reset();
}

/** destructor **/
HashFunctionSHA384_C::~HashFunctionSHA384_C()
{
    //
}

/** virtual function **/
/** reset            **/
//! Resets the object, it can be used again for other data.
/// \return void
/// \param  void
void HashFunctionSHA384_C::reset(void)
{
    HashFunctionStub_C::reset_b();
    mState[0] = 0xcbbb9d5dc1059ed8ULL;
    mState[1] = 0x629a292a367cd507ULL;
    mState[2] = 0x9159015a3070dd17ULL;
    mState[3] = 0x152fecd8f70e5939ULL;
    mState[4] = 0x67332667ffc00b31ULL;
    mState[5] = 0x8eb44a8768581511ULL;
    mState[6] = 0xdb0c2e0d64f98fa7ULL;
    mState[7] = 0x47b5481dbefa4fa4ULL;
}

/** virtual function **/
/** transform_block  **/
//! Feeds a new block of data in the digester.
/// \return void
/// \param   uint8_t *data
///         Pointer to a piece of data of get_transform_size size.
void HashFunctionSHA384_C::transform_block( uint8_t *data)
{
    uint64_t W[80];

    W[ 0] = byteswap(K64( 0));
    W[ 1] = byteswap(K64( 1));
    W[ 2] = byteswap(K64( 2));
    W[ 3] = byteswap(K64( 3));
    W[ 4] = byteswap(K64( 4));
    W[ 5] = byteswap(K64( 5));
    W[ 6] = byteswap(K64( 6));
    W[ 7] = byteswap(K64( 7));
    W[ 8] = byteswap(K64( 8));
    W[ 9] = byteswap(K64( 9));
    W[10] = byteswap(K64(10));
    W[11] = byteswap(K64(11));
    W[12] = byteswap(K64(12));
    W[13] = byteswap(K64(13));
    W[14] = byteswap(K64(14));
    W[15] = byteswap(K64(15));

    for(uint32_t i = 16; i < 80; i++ )
        W[i] = SHA4S1(W[i-2]) + W[i-7] + SHA4S0(W[i-15]) + W[i-16];

    uint64_t a = mState[0];
    uint64_t b = mState[1];
    uint64_t c = mState[2];
    uint64_t d = mState[3];
    uint64_t e = mState[4];
    uint64_t f = mState[5];
    uint64_t g = mState[6];
    uint64_t h = mState[7];

    for(uint32_t i = 0; i < 80; i += 8)
    {
        SHA4Subround(a, b, c, d, e, f, g, h, W[i  ], SHA4C[i  ]);
        SHA4Subround(h, a, b, c, d, e, f, g, W[i+1], SHA4C[i+1]);
        SHA4Subround(g, h, a, b, c, d, e, f, W[i+2], SHA4C[i+2]);
        SHA4Subround(f, g, h, a, b, c, d, e, W[i+3], SHA4C[i+3]);
        SHA4Subround(e, f, g, h, a, b, c, d, W[i+4], SHA4C[i+4]);
        SHA4Subround(d, e, f, g, h, a, b, c, W[i+5], SHA4C[i+5]);
        SHA4Subround(c, d, e, f, g, h, a, b, W[i+6], SHA4C[i+6]);
        SHA4Subround(b, c, d, e, f, g, h, a, W[i+7], SHA4C[i+7]);
    }

    mState[0] += a;
    mState[1] += b;
    mState[2] += c;
    mState[3] += d;
    mState[4] += e;
    mState[5] += f;
    mState[6] += g;
    mState[7] += h;
}

/** virtual function **/
/** finish           **/
//! Finishes the algorithm, no data can be fed again.
/// \return void
/// \param  void
void HashFunctionSHA384_C::finish(void)
{
    uint8_t padding[128];
    uint8_t len[16];
    memset(padding, 0, 128);
    padding[0] = 0x80;

    ((uint64_t*)len)[0] = byteswap((uint64_t)(get_processed() >> 61));
    ((uint64_t*)len)[1] = byteswap((uint64_t)(get_processed() << 3));

    uint32_t buffered = get_processed() & 0x7F;
    uint32_t paddingn = (buffered < 112) ? (112 - buffered) : (240 - buffered);

    feed(padding, paddingn);
    feed(len, 16);

    mState[0] = byteswap(mState[0]);
    mState[1] = byteswap(mState[1]);
    mState[2] = byteswap(mState[2]);
    mState[3] = byteswap(mState[3]);
    mState[4] = byteswap(mState[4]);
    mState[5] = byteswap(mState[5]);
}

/** virtual function **/
/** get_hash         **/
//! Returns the hash.
/// \return void
/// \param   uint8_t *hash
///         A pointer to a location where you want to store the hash.
void HashFunctionSHA384_C::get_hash( uint8_t *hash)
{
    for(uint32_t a = 0; a < 48; a++)
        hash[a] = ((uint8_t*)mState)[a];
}

} // namespace Crypto
} // namespace Myth
